
#include <cstdlib>
#include <iostream>
#include <sys/wait.h> // 仅在Unix-like系统上需要
#include<vector>
#include<cctype>
#include<string>
#include<algorithm>
#include<atomic>
#include<thread>
#include<chrono>
#include<fstream>
#include <zip.h>



std::atomic<bool>success{ false };
std::atomic<int>finish{ 0 };


inline bool isPass(const char ch)
{
    return isprint(ch);
}


//密码   最终输出目录    需要测试密码的zip压缩包
void extract(const std::vector<std::string>& passwdVec, const std::string& outputDir, const std::string& zipName)
{
    std::string escaped;

    int result, err, i;
    zip_t* archive;

    zip_file_t* file;
    zip_int64_t archiveNum;



    archive = zip_open(zipName.c_str(), ZIP_RDONLY, &err);
    if (!archive)
        return;

    archiveNum = zip_get_num_entries(archive, 0);

    for (auto& password : passwdVec)
    {
        if (success.load())
        {
            zip_close(archive);
            break;
        }
        escaped.clear();
        for (char c : password)
        {
            switch (c)
            {
            case '"':
                escaped += "\\\"";
                break;
            case '\\':
                escaped += "\\\\";
                break;
            default:
                escaped += c;
                break;
            }
        }

        if (!escaped.empty())
        {
            result = zip_set_default_password(archive, escaped.c_str());
            if (result)
            {
                zip_close(archive);
                break;
            }
        }

        for (i = 0; i < archiveNum; i++)
        {
            file = zip_fopen_index(archive, i, 0);
            if (file)
                zip_fclose(file);
            else
                break;
        }

        if (i == archiveNum)
        {
            success.store(true);
            std::ofstream(outputDir + "pass.txt", std::ios::app | std::ios::binary) << password << '\n';
            zip_close(archive);
            break;
        }
    }
    finish.store(finish.load() + 1);
}


int main()
{
    auto startTime{ std::chrono::high_resolution_clock::now() }, endTime{ std::chrono::high_resolution_clock::now() };

    std::vector<std::string>vec,
        vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15, vec16;
    char ch;
    std::size_t begin{}, end{};

    //maxLen为密码长度，根据需要调整这个
    int len{ 0 }, maxLen{ 3 }, i;

    //要解压的压缩包  只需要设置要解压的压缩包和解压后输出的路径即可，其他不用动
    const std::string fileName{ "/home/download/test.zip" };
    //解压后输出的路径
    const std::string outputDir{ "/home/download/test" };

    unsigned int num_cores = std::thread::hardware_concurrency();


    std::ofstream(outputDir + "pass.txt", std::ios::trunc | std::ios::binary) << "";


    char buf[100]{};
    char* pos, * writePos;
    int result, exit_status;



    for (ch = 0; ch != -128; ++ch)
    {
        if (isPass(ch))
            vec.emplace_back(std::string(1, ch));
    }


    begin = 0, end = vec.size();

    while (++len != maxLen)
    {

        for (i = begin; i != end; ++i)
        {
            pos = buf;
            std::copy(vec[i].cbegin(), vec[i].cend(), pos);
            pos += vec[i].size();
            writePos = pos;
            for (ch = 0; ch != -128; ++ch)
            {
                if (isPass(ch))
                {
                    *writePos++ = ch;
                    *writePos++ = 0;
                    vec.emplace_back(buf);
                    writePos = pos;
                }
            }
        }

        begin = end, end = vec.size();
    }


    i = -1;
    for (auto& pass : vec)
    {

        switch (++i % num_cores)
        {
        case 0:
            vec1.emplace_back(pass);
            if (num_cores == 1)
                i = -1;
            break;
        case 1:
            vec2.emplace_back(pass);
            if (num_cores == 2)
                i = -1;
            break;
        case 2:
            vec3.emplace_back(pass);
            if (num_cores == 3)
                i = -1;
            break;
        case 3:
            vec4.emplace_back(pass);
            if (num_cores == 4)
                i = -1;
            break;
        case 4:
            vec5.emplace_back(pass);
            if (num_cores == 5)
                i = -1;
            break;
        case 5:
            vec6.emplace_back(pass);
            if (num_cores == 6)
                i = -1;
            break;
        case 6:
            vec7.emplace_back(pass);
            if (num_cores == 7)
                i = -1;
            break;
        case 7:
            vec8.emplace_back(pass);
            if (num_cores == 8)
                i = -1;
            break;
        case 8:
            vec9.emplace_back(pass);
            if (num_cores == 9)
                i = -1;
            break;
        case 9:
            vec10.emplace_back(pass);
            if (num_cores == 10)
                i = -1;
            break;
        case 10:
            vec11.emplace_back(pass);
            if (num_cores == 11)
                i = -1;
            break;
        case 11:
            vec12.emplace_back(pass);
            if (num_cores == 12)
                i = -1;
            break;
        case 12:
            vec13.emplace_back(pass);
            if (num_cores == 13)
                i = -1;
            break;
        case 13:
            vec14.emplace_back(pass);
            if (num_cores == 14)
                i = -1;
            break;
        case 14:
            vec15.emplace_back(pass);
            if (num_cores == 15)
                i = -1;
            break;
        case 15:
            vec16.emplace_back(pass);
            if (num_cores == 16)
                i = -1;
            break;
        default:

            break;
        }
    }

    vec.clear();
    vec = std::vector<std::string>();


    std::thread t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16;

    if (num_cores > 0)
    {
        t1 = std::thread(extract, vec1, outputDir, fileName);
        t1.detach();
    }
    if (num_cores > 1)
    {
        t2 = std::thread(extract, vec2, outputDir, fileName);
        t2.detach();
    }
    if (num_cores > 2)
    {
        t3 = std::thread(extract, vec3, outputDir, fileName);
        t3.detach();
    }
    if (num_cores > 3)
    {
        t4 = std::thread(extract, vec4, outputDir, fileName);
        t4.detach();
    }
    if (num_cores > 4)
    {
        t5 = std::thread(extract, vec5, outputDir, fileName);
        t5.detach();
    }
    if (num_cores > 5)
    {
        t6 = std::thread(extract, vec6, outputDir, fileName);
        t6.detach();
    }
    if (num_cores > 6)
    {
        t7 = std::thread(extract, vec7, outputDir, fileName);
        t7.detach();
    }
    if (num_cores > 7)
    {
        t8 = std::thread(extract, vec8, outputDir, fileName);
        t8.detach();
    }
    if (num_cores > 8)
    {
        t9 = std::thread(extract, vec9, outputDir, fileName);
        t9.detach();
    }
    if (num_cores > 9)
    {
        t10 = std::thread(extract, vec10, outputDir, fileName);
        t10.detach();
    }
    if (num_cores > 10)
    {
        t11 = std::thread(extract, vec11, outputDir, fileName);
        t11.detach();
    }
    if (num_cores > 11)
    {
        t12 = std::thread(extract, vec12, outputDir, fileName);
        t12.detach();
    }
    if (num_cores > 12)
    {
        t13 = std::thread(extract, vec13, outputDir, fileName);
        t13.detach();
    }
    if (num_cores > 13)
    {
        t14 = std::thread(extract, vec14, outputDir, fileName);
        t14.detach();
    }
    if (num_cores > 14)
    {
        t15 = std::thread(extract, vec15, outputDir, fileName);
        t15.detach();
    }
    if (num_cores > 15)
    {
        t16 = std::thread(extract, vec16, outputDir, fileName);
        t16.detach();
    }





    while (!success.load() && finish.load()!= num_cores)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    endTime = std::chrono::high_resolution_clock::now();






    return 0;
}


